package com.zhny.protocol_v3_008.network;

import java.io.IOException;
import java.util.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.sun.istack.internal.NotNull;
import com.zhny.meddleware.IMessenger;
import com.zhny.meddleware.Mediator;
import com.zhny.protocol_v3_008.constant.*;
import com.zhny.protocol_v3_008.creator.PackageCreator;
import com.zhny.protocol_v3_008.model.Datagram;

import com.zhny.util.XMLReaderUtil;
import com.zhny.vo.XMLSite;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author Create By Alex On 2017年11月25日 下午4:39:22
 * @review Review By Alex On 2018/4/9 0:28
 */
//数据包发送者
@Component
public class Sender extends AbsNetwork implements IMessenger {

    @Autowired
    private PackageCreator pc;

    private TelemeterTask packageTask;
    private HeartTask heartTask;

    @Autowired
    private Mediator mediator;

    @Autowired
    private Receiver receiver;

    //错误信息
    private int failedMsg;

    //心跳包
    private Datagram heartPack;

    private TreeMap<Integer, Short> deviceTable = new TreeMap<>();
    private TreeMap<Integer, String> dtuTable = new TreeMap<>();

    // 注册失败的次数
    private int failedCount = 0;

    private boolean firstStart = true;
    private int currentType;

    @Value("${network.telemeterTimeInterval}")
    private int telemeterTimeInterval;
    @Value("${network.heartBeatTimeInterval}")
    private int heartBeatTimeInterval;

    /**
     * 读取母结点下的所有子节点
     *
     * @param baseName 总站点
     */
    public void setDtuTable(String baseName) {
        if (dtuTable.size() == 0) {
            Vector<XMLSite> sites = XMLReaderUtil.getSites(baseName);
            for (XMLSite site : sites) {
                dtuTable.put(Integer.valueOf(site.getDeviceId()), site.getDtu());
            }
        }
    }

    /**
     * 发送单一站点的注册信息，发送完成后创建心跳信息，同时向deviceTable中添加该站点项
     */
    public void register(int deviceFlag, short deviceType) {
        mediator.sendMsgToView("开始注册!", null);
        mediator.sendMsgToReceiver(PackageType.REGISTER);
        currentType = PackageType.REGISTER;

        //创建注册数据包
        Datagram datagram = pc.createRegisterDatagram(deviceFlag, deviceType);
        mediator.sendMsgToView(datagram.toString(), datagram.toMap());
        //发送注册信息
        try {
            os.write(pc.createPackage(datagram));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //添加至设备列表
        deviceTable.put(deviceFlag, deviceType);
        //创建心跳包
        try {
            heartPack = pc.createHearBeatDatagram(deviceTable);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        receiver.receive();
    }

    /**
     * 发送多设备的注册信息，发送完成后创建心跳信息，同时向deviceTable中添加所有列表项
     *
     * @param deviceTable 多设备映射表
     */
    public void register(TreeMap<Integer, Short> deviceTable) {
        mediator.sendMsgToView("开始注册!", null);
        mediator.sendMsgToReceiver(PackageType.REGISTER);
        currentType = PackageType.REGISTER;

        Datagram datagram = null;
        try {
            datagram = pc.createRegisterDatagram(deviceTable);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        if (datagram != null) {
            mediator.sendMsgToView("注册信息：" + datagram.toString(), datagram.toMap());
            //发送注册包
            try {
                os.write(pc.createPackage(datagram));
            } catch (IOException e) {
                e.printStackTrace();
            }
            //添加至设备列表
            this.deviceTable.putAll(deviceTable);
        } else {
            mediator.sendMsgToView("注册信息为空！", null);
        }

        try {
            heartPack = pc.createHearBeatDatagram(this.deviceTable);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        receiver.receive();
    }

    private void telemeter(Integer deviceFlag, Short deviceType) {
        mediator.sendMsgToReceiver(PackageType.TELEMETRY);
        currentType = PackageType.TELEMETRY;

        Datagram datagram = null;
        try {
            datagram = pc.createTelemeterDatagram(deviceFlag, deviceType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        try {
            os.write(pc.createPackage(datagram));
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (datagram != null) {
            mediator.sendMsgToView("发送遥测数据包：" + datagram.toString(), datagram.toMap());
        }

        receiver.receive();
    }

    public void telemeter(@NotNull TreeMap<Integer, Short> deviceTable) {
        mediator.sendMsgToView("发送遥测数据包", null);
        for (Map.Entry<Integer, Short> entry : deviceTable.entrySet()) {
            telemeter(entry.getKey(), entry.getValue());
        }
    }

    //TODO: 更改为private
    public void heartBeat() {
        mediator.sendMsgToView("发送心跳包", null);
        mediator.sendMsgToReceiver(PackageType.HEART);
        currentType = PackageType.HEART;

        heartPack.setDate((int) (System.currentTimeMillis() / 1000));
        try {
            os.write(pc.createPackage(heartPack));
            mediator.sendMsgToView("发送心跳：" + heartPack.toString(), heartPack.toMap());
        } catch (IOException e) {
            e.printStackTrace();
        }
        receiver.receive();
    }


    /**
     * 清除相应的设备，更新心跳包数据
     *
     * @param deviceFlag 设备标识符
     */
    public void deleteDevice(int deviceFlag) {
        deviceTable.remove(deviceFlag);
        if (deviceTable.size() == 0) {
            heartTask.flag = false;
            packageTask.flag = false;
            mediator.sendMsgToView("所有设备都已离线！", null);
            return;
        }
        //更新心跳包
        try {
            heartPack = pc.createHearBeatDatagram(deviceTable);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }

    //TODO: 错误处理
    @Override
    public void handleMessage(int message) {
        failedMsg = message;
        switch (currentType) {
            case PackageType.REGISTER:
                if (failedCount < 3) {
                    failedCount++;
                    mediator.sendMsgToView("第" + failedCount + "次注册！", null);
                    register(deviceTable);
                } else {
                    mediator.sendMsgToView("三次注册失败！请检查您的网络或联系维修人员！", null);
                    close();
                }
                break;
            case PackageType.HEART:
                break;
            case PackageType.TELEMETRY:
                break;
        }
    }

    public void start() {
        if (packageTask == null) {
            //设置数据包发送任务
            packageTask = new TelemeterTask();
//            System.out.println("packageTask started!");
            packageTask.start();
        }

        if (heartTask == null) {
            //设置心跳发送任务
            heartTask = new HeartTask();
//            System.out.println("heartTask started!");
            heartTask.start();
        }

        if (packageTask != null && heartTask != null && !heartTask.flag) {
            if (heartTask.isAlive())
                heartTask.flag = true;
            else {
                heartTask = new HeartTask();
                heartTask.start();
            }
            if (packageTask.isAlive())
                packageTask.flag = true;
            else {
                packageTask = new TelemeterTask();
                packageTask.start();
            }
        }
    }

    /**
     * 结束后台
     */
    public void close() {
        if (packageTask != null) {
            packageTask.flag = false;
            packageTask.interrupt();
        }
        if (heartTask != null) {
            heartTask.flag = false;
            heartTask.interrupt();
        }
        super.close();
    }

    private final Boolean locked = false;

    /**
     * @review Review By Alex On 2018/4/10 15:43
     */
    class TelemeterTask extends Thread {
        boolean flag = true;

        public void run() {
            while (flag) {
                synchronized (locked) {
                    telemeter(deviceTable);
                }
                try {
                    Thread.sleep(telemeterTimeInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class HeartTask extends Thread {
        boolean flag = true;

        public void run() {
            while (flag) {
                synchronized (locked) {
                    heartBeat();
                }
                try {
                    Thread.sleep(heartBeatTimeInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
